﻿#include "tap_api_market.h"
#include <filesystem>
#include <time_utils.hpp>
#include <params.hpp>
#include <log_wapper.hpp>
#include <../../api/TAP_V9_20200808/TapAPIError.h>

// 构造函数：初始化行情 API 对象并加载相关配置
// 参数：
// - id_excg_map: 交易所 ID 映射
// - config: 行情参数配置
tap_api_market::tap_api_market(const std::shared_ptr<std::unordered_map<std::string, std::string>>& id_excg_map, const params& config) noexcept
    : asyn_actual_market(id_excg_map)   // 调用基类构造函数，初始化 ID 映射表
    , _md_api(nullptr)                  // 初始化 API 指针为空
    , _port(0)                          // 初始化端口为 0
    , _process_mutex(_mutex)            // 使用 std::unique_lock 关联互斥锁
    , _is_inited(false)                 // 初始化为未初始化状态
    , _trading_day(0)                   // 初始化交易日为 0
{
    // 从配置中读取必要的参数
    try
    {
        _ip = config.get<std::string>("ip");              // 获取服务器 IP 地址
        _port = config.get<uint16_t>("port");             // 获取服务器端口
        _userid = config.get<std::string>("userid");      // 获取用户 ID
        _password = config.get<std::string>("passwd");    // 获取用户密码
        _authcode = config.get<std::string>("authcode");  // 获取认证码
    }
    catch (...)
    {
        // 捕获异常并记录配置错误
        LOG_ERROR("tap_api_market init error ");
    }

    // 加载 TAP 行情动态库
    _market_handle = dll_helper::load_library("TapQuoteAPI");
    if (_market_handle)
    {
        // 从动态库中获取创建和销毁 API 的函数指针
        _tap_creator = (market_creator)dll_helper::get_symbol(_market_handle, "CreateTapQuoteAPI");
        _tap_destroyer = (market_destroyer)dll_helper::get_symbol(_market_handle, "FreeTapQuoteAPI");
    }
    else
    {
        // 记录加载动态库失败的错误
        LOG_ERROR("tap_api_market TapQuoteAPI load error ");
    }

    LOG_INFO("tap market init");  // 记录初始化信息
    // 初始化日志级别和数据路径（可以启用）
    // SetTapQuoteAPILogLevel(APILOGLEVEL_DEBUG);
    // SetTapQuoteAPIDataPath("md_log");
}

// 析构函数：清理资源
tap_api_market::~tap_api_market() noexcept
{
    // 析构函数内容为空，资源在登出中已处理
}

// 登录函数：用于登录行情服务器
// 返回值：登录成功返回 true，否则返回 false
bool tap_api_market::login() noexcept
{
    // 设置应用信息
    TapAPIApplicationInfo stAppInfo;
    strcpy(stAppInfo.AuthCode, _authcode.c_str()); // 设置认证码
    const char* log_path = "./log/api";            // 日志文件路径
    if (!std::filesystem::exists(log_path))
    {
        // 创建日志目录
        std::filesystem::create_directories(log_path);
    }
    strcpy(stAppInfo.KeyOperationLogPath, log_path); // 设置操作日志路径

    // 创建行情 API 实例
    TAPIINT32 iResult = TAPIERROR_SUCCEED;
    _md_api = _tap_creator(&stAppInfo, iResult);  // 调用创建函数，传入应用信息
    if (NULL == _md_api)
    {
        // 记录错误并返回失败
        LOG_FATAL("tap_api_market login error :", iResult);
        return false;
    }

    // 设置回调接口
    _md_api->SetAPINotify(this);

    // 设置服务器 IP 和端口
    TAPIINT32 iErr = _md_api->SetHostAddress(_ip.c_str(), _port);
    if (TAPIERROR_SUCCEED != iErr)
    {
        // 设置地址失败，记录错误并返回
        LOG_FATAL("SetHostAddress Error:", iErr);
        return false;
    }

    // 构建登录请求并发送
    TapAPIQuoteLoginAuth stLoginAuth;
    memset(&stLoginAuth, 0, sizeof(stLoginAuth));      // 初始化登录请求结构体
    strcpy(stLoginAuth.UserNo, _userid.c_str());       // 设置用户 ID
    strcpy(stLoginAuth.Password, _password.c_str());   // 设置用户密码
    stLoginAuth.ISModifyPassword = APIYNFLAG_NO;       // 不修改密码
    stLoginAuth.ISDDA = APIYNFLAG_NO;                  // 不启用 DDA
    iErr = _md_api->Login(&stLoginAuth);               // 发送登录请求
    if (TAPIERROR_SUCCEED != iErr)
    {
        // 登录失败，记录错误并返回
        LOG_FATAL("Login Error:", iErr);
        return false;
    }

    // 等待 API 初始化完成
    _process_signal.wait(_process_mutex);  // 使用条件变量等待登录完成
    _is_inited = true;                     // 标记初始化完成
    return true;                           // 返回登录成功
}

// 登出函数：用于登出行情服务器并清理资源
void tap_api_market::logout() noexcept
{
    // 清除映射表
    _id_excg_map->clear();
    if (_md_api)
    {
        // 销毁行情 API 实例
        _tap_destroyer(_md_api);
        _md_api = nullptr;  // 置空指针，防止重复操作
    }
    _is_inited = false;  // 重置初始化状态
}

// API 准备完成回调
void tap_api_market::OnAPIReady() noexcept
{
    // 记录 API 准备完成的信息
    LOG_INFO("OnAPIReady :", _ip.c_str(), _port);
    _process_signal.notify_all();  // 通知登录流程完成
}

// 登录响应回调：处理登录结果
void tap_api_market::OnRspLogin(TAPIINT32 errorCode, const TapAPIQuotLoginRspInfo* info) noexcept
{
    if (TAPIERROR_SUCCEED == errorCode)
    {
        // 登录成功
        LOG_INFO("登录成功，等待API初始化...");
        if (info)
        {
            _trading_day = date_to_uint(info->TradeDate); // 保存交易日信息
        }
    }
    else
    {
        // 登录失败，记录错误码
        LOG_ERROR("登录失败，错误码:", errorCode);
        // _process_signal.notify_all(); // 可根据需求解锁等待
    }
}

// 连接断开回调
void tap_api_market::OnDisconnect(TAPIINT32 reasonCode) noexcept
{
    // 记录断开连接的原因代码
    LOG_INFO("tap_api_market OnDisconnect : Reason -> %d", reasonCode);
}

// 行情数据通知回调
void tap_api_market::OnRtnQuote(const TapAPIQuoteWhole* info) noexcept
{
    if (info == nullptr)
    {
        return;  // 如果收到的行情数据为空，直接返回
    }

    PROFILE_INFO(info->Contract.Commodity.CommodityNo);  // 记录行情接收信息

    // 构建 tick 信息
    tick_info tick(
        code_t(info->Contract.Commodity.CommodityNo, info->Contract.ContractNo1, info->Contract.Commodity.ExchangeNo),
        make_daytm(info->DateTimeStamp + 11, true), // 解析行情时间戳
        info->QOpeningPrice,
        info->QClosingPrice,
        info->QHighPrice,
        info->QLowPrice,
        info->QLastPrice,
        info->QPreSettlePrice,
        info->QTotalQty,
        _trading_day, // 使用当前交易日
        static_cast<double_t>(info->QPositionQty),
        {
            std::make_pair(info->QBidPrice[0], static_cast<uint32_t>(info->QBidQty[0])), // 买一价和买一量
            std::make_pair(info->QBidPrice[1], static_cast<uint32_t>(info->QBidQty[1])), // 买二价和买二量
            std::make_pair(info->QBidPrice[2], static_cast<uint32_t>(info->QBidQty[2])), // 买三价和买三量
            std::make_pair(info->QBidPrice[3], static_cast<uint32_t>(info->QBidQty[3])), // 买四价和买四量
            std::make_pair(info->QBidPrice[4], static_cast<uint32_t>(info->QBidQty[4]))  // 买五价和买五量
        },
        {
            std::make_pair(info->QAskPrice[0], static_cast<uint32_t>(info->QAskQty[0])), // 卖一价和卖一量
            std::make_pair(info->QAskPrice[1], static_cast<uint32_t>(info->QAskQty[1])), // 卖二价和卖二量
            std::make_pair(info->QAskPrice[2], static_cast<uint32_t>(info->QAskQty[2])), // 卖三价和卖三量
            std::make_pair(info->QAskPrice[3], static_cast<uint32_t>(info->QAskQty[3])), // 卖四价和卖四量
            std::make_pair(info->QAskPrice[4], static_cast<uint32_t>(info->QAskQty[4]))  // 卖五价和卖五量
        }
    );

    PROFILE_DEBUG(tick.id.get_id());  // 记录行情 ID 信息
    // 触发行情接收事件，传递 tick 数据
    this->fire_event(market_event_type::MET_TickReceived, tick);
}

// 订阅行情响应回调
void tap_api_market::OnRspSubscribeQuote(TAPIUINT32 sessionID, TAPIINT32 errorCode, TAPIYNFLAG isLast, const TapAPIQuoteWhole* info) noexcept
{
    // 记录订阅响应结果
    LOG_INFO("SubMarketData : code ", errorCode);
}

// 取消订阅行情响应回调
void tap_api_market::OnRspUnSubscribeQuote(TAPIUINT32 sessionID, TAPIINT32 errorCode, TAPIYNFLAG isLast, const TapAPIContract* info) noexcept
{
    // 记录取消订阅响应结果
    LOG_INFO("UnSubMarketData : code ", errorCode);
}

// 订阅指定的行情
void tap_api_market::subscribe(const std::set<code_t>& code_list) noexcept
{
    // 遍历合约代码列表并订阅
    for (const auto& it : code_list)
    {
        TapAPIContract stContract;
        memset(&stContract, 0, sizeof(stContract)); // 初始化合约结构体

        // 设置合约信息
        strcpy(stContract.Commodity.ExchangeNo, it.get_excg());         // 设置交易所
        stContract.Commodity.CommodityType = TAPI_COMMODITY_TYPE_FUTURES; // 设置品种类型为期货
        strcpy(stContract.Commodity.CommodityNo, it.get_cmdtid());      // 设置品种编号
        snprintf(stContract.ContractNo1, 11, "%d", it.get_cmdtno());    // 设置合约编号

        stContract.CallOrPutFlag1 = TAPI_CALLPUT_FLAG_NONE; // 无看涨看跌
        stContract.CallOrPutFlag2 = TAPI_CALLPUT_FLAG_NONE;

        // 发送订阅请求
        auto iErr = _md_api->SubscribeQuote(&_reqid, &stContract);
        if (TAPIERROR_SUCCEED != iErr)
        {
            // 记录订阅错误
            LOG_ERROR("SubscribeQuote Error:", iErr);
        }
    }
}

// 取消订阅指定的行情
void tap_api_market::unsubscribe(const std::set<code_t>& code_list) noexcept
{
    // 遍历合约代码列表并取消订阅
    for (const auto& it : code_list)
    {
        TapAPIContract stContract;
        memset(&stContract, 0, sizeof(stContract)); // 初始化合约结构体

        // 设置合约信息
        strcpy(stContract.Commodity.ExchangeNo, it.get_excg());         // 设置交易所
        stContract.Commodity.CommodityType = TAPI_COMMODITY_TYPE_FUTURES; // 设置品种类型为期货
        strcpy(stContract.ContractNo1, it.get_id());                    // 设置合约编号

        stContract.CallOrPutFlag1 = TAPI_CALLPUT_FLAG_NONE; // 无看涨看跌
        stContract.CallOrPutFlag2 = TAPI_CALLPUT_FLAG_NONE;

        // 发送取消订阅请求
        auto iErr = _md_api->UnSubscribeQuote(&_reqid, &stContract);
        if (TAPIERROR_SUCCEED != iErr)
        {
            // 记录取消订阅错误
            LOG_ERROR("UnSubscribeQuote Error:", iErr);
        }
    }
}
